package com.dycong.common.common;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Administrator
 */
public class ThreadLocalDateUtil {

    public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_TIME_MILLI = "yyyy-MM-dd HH:mm:ss:SSS";
    public static final String DATE = "yyyy-MM-dd";
    public static final String TIME = "HH:mm:ss";


    private static ThreadLocal<Map<String, DateFormat>> DATE_FORMAT_THREAD_LOCAL = new ThreadLocal<>();

    /**
     * todo SimpleDateFormat继承了DateFormat,在DateFormat中定义了一个protected属性的 Calendar类的对象：calendar。只是因为Calendar类的概念复杂，牵扯到时区与本地化等等，
     * todo Jdk的实现中使用了成员变量来传递参数，这就造成在多线程的时候会出现错误。
     * todo 这个问题背后隐藏着一个更为重要的问题--无状态：无状态方法的好处之一，就是它在各种环境下，都可以安全的调用。衡量一个方法是否是有状态的，就看它是否改动了其它的东西，比如全局变量，比如实例的字段。
     * todo format方法在运行过程中改动了SimpleDateFormat的calendar字段，所以，它是有状态的。
     *
     * @return
     */
    public static DateFormat getDateFormat(String formatPattern) {
        Map<String, DateFormat> dateFormatMap = DATE_FORMAT_THREAD_LOCAL.get();
        if (null == dateFormatMap) {
            dateFormatMap = new HashMap<>();
        }
        DateFormat df = dateFormatMap.get(formatPattern);
        if (null == df) {
            df = new SimpleDateFormat(formatPattern);
            dateFormatMap.put(formatPattern, df);
            DATE_FORMAT_THREAD_LOCAL.set(dateFormatMap);
        }
        return df;
    }

    public static String formatDate(Date date, String pattern) throws ParseException {
        return getDateFormat(pattern).format(date);
    }

    public static Date parse(String strDate, Date date, String pattern) throws ParseException {
        return getDateFormat(pattern).parse(strDate);
    }

    public static void main(String[] args) throws ParseException {
        System.out.println(formatDate(new Date(),"yyyy-MM-dd HH:mm:ss"));
        System.out.println(formatDate(new Date(),"yyyy/MM/dd HH:mm:ss"));
        System.out.println(formatDate(new Date(),"yyyy年MM月dd日 HH时mm分ss秒"));
        System.out.println(formatDate(new Date(),"yyyy年MM月dd日"));
        System.out.println(formatDate(new Date(),"yyyy年MM月dd日"));
        System.out.println(formatDate(new Date(),"yyyy年MM月dd日"));
        System.out.println(formatDate(new Date(),DATE_TIME_MILLI));
    }

    /**
     * todo ThreadLocal.withInitial()
     * Creates a thread local variable. The initial value of the variable is
     * determined by invoking the {@code get} method on the {@code Supplier}.
     *
     * @param <S> the type of the thread local's value
     * @param supplier the supplier to be used to determine the initial value
     * @return a new thread local variable
     * @throws NullPointerException if the specified supplier is null
     * @since 1.8
     */
    public static final ThreadLocal<SimpleDateFormat> FULL_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    public static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
    public static final ThreadLocal<SimpleDateFormat> TIME_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss"));
}
